programming4us
           
 
 
Programming

Context and Interception : Custom Component Services (part 3) - The Transaction Management Service

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
8/9/2011 3:38:53 PM

4. The Transaction Management Service

.NET 2.0 introduces an innovative transaction management service in the System.Transactions namespace. A transaction managed by System.Transactions is stored in the thread local storage and is called the ambient transaction. System.Transactions-enabled resource managers (such as SQL Server 2005) detect the ambient transaction and automatically enlist in the transaction, similar to the auto-enlistment of Enterprise Services resource managers. This for the most part eliminates the need to manage the transaction yourself. The main feature of System.Transactions is its ability to automatically promote the transaction across transaction managers, from the lightweight transaction manager (LTM) used with a single object and a single durable resource to the OleTx transaction manager used to manage a distributed transaction. For more information about System.Transactions, see my whitepaper "Introducing System.Transactions in the Microsoft .NET Framework Version 2" (MSDN, April 2005).

When not using Enterprise Services (and until the release of Indigo), System.Transactions supports only an explicit programming model. You typically interact with an object of type TransactionScope, defined as:

    public class TransactionScope : IDisposable
{
public TransactionScope( );
public TransactionScope(TransactionScopeOption scopeOptions);
//Additional constructors

public void Complete( );
public void Dispose( );
}

As the name implies, the TransactionScope class is used to scope a code section with a transaction, as demonstrated in Example 11-6. Internally in its constructor, the TransactionScope object creates a transaction (an LTM transaction, by default) and assigns it as the ambient transaction. TransactionScope is a disposable object—the transaction will end once the Dispose( ) method is called (the end of the using statement in Example 5).

Example 5. Using the TransactionScope class
TransactionScope scope = new TransactionScope( );
using(scope)
{
/* Perform transactional work here */

//No errors - commit transaction
scope.Complete( );
}

The TransactionScope object has no way of knowing whether the transaction should commit or abort. To address this, TransactionScope internally maintains a consistency bit, which is set by default to false. You can set the consistency bit to true by calling the Complete( ) method. If the consistency bit is set to false when the transaction ends, the transaction will abort; otherwise, it will try to commit. Note that once you call Complete( ), there is no way to set the consistency bit back to false.

4.1. Transaction flow management

Transaction scopes can nest both directly and indirectly. A direct scope nesting is simply one scope nested inside another. An indirect scope nesting occurs when you call a method that uses a TransactionScope object from within a method that uses its own scope. You can also have multiple scope nesting, involving both direct and indirect nesting. The topmost scope is referred to as the root scope. The question is, of course, what is the relation between the root scope and all the nested scopes? How will nesting a scope affect the ambient transaction? To address these questions, the TransactionScope class provides several overloaded constructors that accept an enum of the type TransactionScopeOption, defined as:

    public enum TransactionScopeOption
{
Required,
RequiresNew,
Suppress
}

The value of TransactionScopeOption lets you control whether the scope takes part in a transaction, and, if so, whether it will join the ambient transaction or be the root scope of a new transaction. For example, here is how you specify the value of the TransactionScopeOption in the scope's constructor:

    TransactionScope scope;
scope = new TransactionScope(TransactionScopeOption.Required);
using(scope)
{...}

The default value for the scope option is TransactionScopeOption.Required. The TransactionScope object determines which transaction to belong to when it is constructed. Once determined, the scope will always belong to that transaction. TransactionScope bases its decision on two factors: whether an ambient transaction is present and the value of the TransactionScopeOption parameter.

A TransactionScope object has three options:

  • Join the ambient transaction.

  • Be a new scope root; that is, start a new transaction and have that transaction be the new ambient transaction inside its own scope.

  • Not take part in a transaction at all.

If the scope is configured with TransactionScopeOption.Suppress, it will never be part of a transaction, regardless of whether an ambient transaction is present.

If the scope is configured with TransactionScopeOption.Required, and an ambient transaction is present, the scope will join that transaction. If, on the other hand, there is no ambient transaction, the scope will create a new transaction and become the root scope.

If the scope is configured with TransactionScopeOption.RequiresNew, it will always be the root scope. It will start a new transaction, and its transaction will be the new ambient transaction inside the scope.

The way the values of TransactionScopeOption affect the flow of the transaction is analogous to the way the integer constants provided to the Synchronization attribute control the flow of the synchronization domain.


4.2. Declarative transaction support

You can use context-bound objects and call interception to provide declarative support for System.Transactions. You will need to install a server context sink that wraps the call to the next sink down the chain in a TransactionScope. Example 6 shows the TransactionAttribute class. Obviously, you will also need a context attribute that adds a context property that installs the sink. These two classes (TransactionAttribute and TransactionalProperty, respectively) are very similar to LogbookAttribute and LogContextProperty. The TransactionAttribute's constructor accepts an enum of the type TransactionScopeOption, indicating how the transaction should flow through this context-bound object. The default constructor uses TransactionScopeOption.Required.

Example 6. The TransactionAttribute class
using System.Transactions;

[AttributeUsage(AttributeTargets.Class)]
public class TransactionAttribute : ContextAttribute
{
TransactionScopeOption m_TransactionOption;

public TransactionAttribute( ) : this(TransactionScopeOption.Required)
{}

public TransactionAttribute(TransactionScopeOption transactionOption) :
base("TransactionAttribute")
{
m_TransactionOption = transactionOption;
}
//Add a new transaction property to the new context
public override void GetPropertiesForNewContext(IConstructionCallMessage ctor)
{
IContextProperty transactional;
transactional = new TransactionalProperty(m_TransactionOption);
ctor.ContextProperties.Add(transactional);
}
//Provides a private context
public override bool IsContextOK(Context ctx,
IConstructionCallMessage ctorMsg)
{
return false;
}
}



The TransactionalProperty class installs the TransactionSink class as a server context sink, providing it with the transaction scope option:

    public class TransactionalProperty: IContextProperty,
IContributeServerContextSink
{
TransactionScopeOption m_TransactionOption;

public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
IMessageSink transactionSink;
transactionSink = new TransactionSink(nextSink,m_TransactionOption);
return transactionSink;
}
//Rest of the implementation
}



The interesting work, of course, is done by TransactionSink, shown in Example 7.

Example 7. The TransactionSink class provides a transactional context
public class TransactionSink : IMessageSink
{
IMessageSink m_NextSink;
TransactionScopeOption m_TransactionOption;

public TransactionSink(IMessageSink nextSink,
TransactionScopeOption transactionOption)
{
m_TransactionOption = transactionOption;
m_NextSink = nextSink;
}

public IMessageSink NextSink
{
get
{
return m_NextSink;
}
}
public IMessage SyncProcessMessage(IMessage msg)
{
IMethodReturnMessage returnedMessage = null;

Exception exception;
TransactionScope scope = new TransactionScope(m_TransactionOption);
using(scope)
{
try
{
returnedMessage = (IMethodReturnMessage)m_NextSink.
SyncProcessMessage(msg);
exception = returnedMessage.Exception;
}
catch(Exception sinkException)
{
exception = sinkException;
}
if(exception == null)
{
scope.Complete( );
}
return returnedMessage;
}
}
public IMessageCtrl AsyncProcessMessage(IMessage msg,IMessageSink replySink)
{
string message = "Transactional calls must be synchronous"
throw new InvalidOperationException(message);
}
}



In SyncProcessMessage( ), TransactionSink constructs a new TransactionScope object, passing its constructor the original value of the TransactionScopeOption enum passed to the Transaction attribute. A using statement with the scope object wraps the call to SyncProcessMessage( ) on the next sink down the chain. If no exception has occurred, SyncProcessMessage( ) calls Complete( ) on the scope and returns.

Example 8 demonstrates the use of the Transaction attribute.

Example 8. Using the Transaction attribute
[Transaction]
public class RootClass : ContextBoundObject
{
public void CreateObjects( )
{
Class1 obj1 = new Class1( );
Class2 obj2 = new Class2( );
Class3 obj3 = new Class3( );
}
}

[Transaction]
public class Class1 : ContextBoundObject
{}

[Transaction(TransactionScopeOption.Suppress)]
public class Class2 : ContextBoundObject
{}

[Transaction(TransactionScopeOption.RequiresNew)]
public class Class3 : ContextBoundObject
{}

Figure 4 depicts the resulting transactions after executing this TransactionDemo( ) method:

    //Non-transactional client
class MyClient
{
public void TransactionDemo( )
{
RootClass root = new RootClass( );
root.CreateObjects( );
}
}

The RootClass class is configured to require a transaction. Since it is being called by a non-transactional client (MyClient is not even context-bound), there is no ambient transaction. RootClass therefore starts a new transaction and becomes its root. When the client calls CreateObjects( ) on the RootClass object, the object creates three other context-bound objects, each configured with a different TransactionScopeOption value. Class1 is configured to require a transaction, so it will join the transaction of the RootClass object. Class2 suppresses any transaction flow, so it will execute without an ambient transaction. Class3 requires a new transaction, so it will be placed in a new transaction.

Figure 4. Transactions flow across transactional contexts

You can add granularity to the Transaction attribute and, instead of being object-based (that is, all calls are transactional), make it method-based. Define a method-level attribute and apply it to the methods you wish to be called transitionally. Have SyncProcessMessage( ) reflect the target method to see if it has the attribute, and if so, wrap the method call with a TransactionScope.

Other -----------------
- Context and Interception : Custom Component Services (part 1) - Building a Custom Context Attribute & Installing a Custom Message Sink
- Software Testing with Visual Studio Team System 2008 : Data-driven unit testing
- Software Testing with Visual Studio Team System 2008 : Unit testing an ASP.NET application
- Microsoft Enterprise Library : Error Management Made Exceptionally Easy - Replacing an Exception & Logging an Exception
- Microsoft Enterprise Library : Error Management Made Exceptionally Easy - Diving in with a Simple Example
- iPhone Programming : Connecting to the Network - Embedding a Web Browser in Your App
- iPhone Programming : Connecting to the Network - Detecting Network Status
- Parallel Programming with Microsoft Visual Studio 2010 : Introduction to Parallel Programming - Software Patterns
- Parallel Programming with Microsoft Visual Studio 2010 : Introduction to Parallel Programming - Multicore Computing & Speedup
- Microsoft ASP.NET 3.5 : Web Services for ASP.NET AJAX Applications (part 2) - Consuming AJAX Web Services
- Microsoft ASP.NET 3.5 : Web Services for ASP.NET AJAX Applications (part 1) - Remote Calls via Web Services
- Microsoft ASP.NET 3.5 : AJAX-Enabled Web Services - Implementing the AJAX Paradigm
- The Art of SEO : Measuring Search Traffic (part 2)
- The Art of SEO : Measuring Search Traffic (part 1)
- Programming Excel with VBA and .NET : Tasks in Visual Basic - Do Math
- Programming Excel with VBA and .NET : Tasks in Visual Basic - Interact with Users
- Context and Interception : The .NET Context
- Context and Interception : .NET Component Services
- Optimizing for Vertical Search : Mobile, Video & Multimedia Search
- Programming WCF Services : Data Contracts - Collections (part 2) - The CollectionDataContract Attribute & Dictionaries
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us